/**
 * License would add here
 */

#ifndef UTILS_JS_ARRAY_H
#define UTILS_JS_ARRAY_H

#include <csignal>
#include <cstdint>
#include <cstring>

#ifndef OHOS_PLATFORM
#include <node_api.h>
#else
#include <napi/native_api.h>
#endif

#include "js_number.h"
#include "js_object.h"
#include "js_value_base.h"
#include "macros.h"

#define IS_ARRAY(type) VALUE_TYPE_CHECK(IsArray(), "array", (type))

class JSArray : public JSObject {
public:
    JSArray(napi_env env)
        : JSObject(env, true)
    {
        napi_create_array(env_, &value_);
        UpdateType();
    }
    JSArray(napi_env env, size_t length)
        : JSObject(env, true)
    {
        napi_create_array_with_length(env, length, &value_);
        UpdateType();
    }
    JSArray(napi_env env, const JSNumber& length)
        : JSObject(env, true)
    {
        napi_create_array_with_length(env, length.GetValue<uint32_t>(), &value_);
        UpdateType();
    }
    JSArray(napi_env env, napi_value value)
        : JSObject(env, value)
    {
        IS_ARRAY(type_);
    }
    JSArray(napi_env env, size_t argc, napi_value* value)
        : JSObject(env, value)
    {
        NAPI_STATUS_CALL(env_, napi_create_array(env_, &value_));
        for (size_t i = 0; i < argc; i++)
        {
            Push(value[i]);
        }
    }
    JSArray(const JSValue& value)
        : JSObject(value)
    {
        IS_ARRAY(type_);
    };

    const JSObject::PropertyLValue<JSArray, uint32_t> Get(uint32_t index) const;

    inline JSObject::PropertyLValue<JSArray, uint32_t> operator[](uint32_t index) const { return Get(index); }

    inline void Set(uint32_t index, const JSValue& value)
    {
        NAPI_STATUS_CALL(env_, napi_set_element(env_, value_, index, value));
    }
    inline void Set(uint32_t index, napi_value value)
    {
        NAPI_STATUS_CALL(env_, napi_set_element(env_, value_, index, value));
    }
    inline void Set(const JSNumber& index, napi_value value)
    {
        Set(index.GetValue<uint32_t>(), value);
    }

    bool Has(uint32_t index)
    {
        bool result;
        NAPI_STATUS_CALL(env_, napi_has_element(env_, value_, index, &result));
        return result;
    }
    bool Has(const JSNumber& index)
    {
        bool result;
        NAPI_STATUS_CALL(env_, napi_has_element(env_, value_, index.GetValue<uint32_t>(), &result));
        return result;
    }

    bool Delete(uint32_t index)
    {
        bool result = false;
        NAPI_STATUS_CALL(env_, napi_delete_element(env_, value_, index, &result));
        return result;
    }
    bool Delete(const JSNumber& index)
    {
        return Delete(index.GetValue<uint32_t>());
    }

    inline void Push(JSValue value) { Set(Length(), value); }
    inline void Push(napi_value value) { Set(Length(), value); }

    uint32_t Length()
    {
        uint32_t length = 0;
        napi_get_array_length(env_, value_, &length);
        return length;
    }

private:
friend class PropertyLValue<JSArray, uint32_t>;
};

#undef IS_ARRAY
#endif /* UTILS_JS_ARRAY_H */
